package com.webserver.core;

import com.webserver.annotation.Controller;
import com.webserver.annotation.RequestMapping;

import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 用来维护所有请求路径与对应的Controller中处理的方法
 */
public class HandlerMapping {
    //封装抽象路径和对应的方法与对象的封装类对象
    private static Map<String, MethodMapping> mappping = new HashMap();

    //用于初始化,扫描的内容
    static {
        initMapping();
    }

    private static void initMapping() {
        /*
         * 扫描com.webserver.controller包下所有被@Controller注解修饰的类,
         * 并判断哪些方法被@RequestMapping注解标注了,如果该方法上注解的值和path值相同,
         * 说明该方法就是处理该请求的方法,利用反射区调用该方法即可
         */
        try {
            /*
             * DispatcherServlet.class.getClassLoader().getResource(".").toURI()
             *   定位的是target/classes目录
             * DispatcherServlet.class.getResource(".").toURI()
             *   定位的是target/classes/com/webserver/core
             * */
            //定位controller目录
            File dir = new File(
                    HandlerMapping.class.getClassLoader().getResource(
                            "./com/webserver/controller").toURI()
            );
            //过滤出该目录下的class文件
            File[] subs = dir.listFiles(f -> f.getName().endsWith(".class"));
            for (File sub : subs) {
                String fileName = sub.getName();//文件名
                String className = fileName.substring(0, fileName.indexOf("."));//类名
                Class cls = Class.forName("com.webserver.controller." + className);
                //判断当前类是否被@Controller注解修饰了
                if (cls.isAnnotationPresent(Controller.class)) {
                    //说明当前类被@Controller注解修饰,就是业务类
                    //实例化当前业务方法所属的对象
                    Object o = cls.newInstance();
                    //获取当前类中的所有方法
                    Method[] methods = cls.getDeclaredMethods();
                    //遍历每个方法
                    for (Method method : methods) {
                        //判断当前方法上是否被@RequestMapping注解修饰了
                        if (method.isAnnotationPresent(RequestMapping.class)) {
                            //说明当前方法被@RequestMapping注解修饰了,就是业务方法
                            //获取方法的@RequestMapping注解
                            RequestMapping rm = method.getAnnotation(RequestMapping.class);
                            //获取该注解中value参数的值(该参数记录的是当前业务方法绑定的请求路径)
                            String path = rm.value();
                            //将业务方法以及所属的对象封装到MethodMapping中
                            MethodMapping methodMapping = new MethodMapping(o, method);
                            mappping.put(path, methodMapping);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * 根据路径返回对应的处理方法
     * @param path
     * @return
     */
    public static MethodMapping getMethod(String path){
        return mappping.get(path);
    }
    public static class MethodMapping {
        private Object controller;//业务类对象
        private Method method;//业务方法

        //提供全参构造
        public MethodMapping(Object controller, Method method) {
            this.controller = controller;
            this.method = method;
        }

        //提供对应的属性的get和set方法
        public Object getController() {
            return controller;
        }

        public void setController(Object controller) {
            this.controller = controller;
        }

        public Method getMethod() {
            return method;
        }

        public void setMethod(Method method) {
            this.method = method;
        }
    }
}
